﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using GC_FFW.BusinessEntities.Abstractions.Interfaces.Forecast;
using GC_FFW.BusinessEntities.Enums.Forecast;
using GC_FFW.BusinessEntities.Forecast;
using GC_FFW.ForecastWriterClient.Helpers;
using GC_FFW.ForecastWriterClient.ViewModels.Parameters;

namespace GC_FFW.ForecastWriterClient.ViewModels
{
	public class MatchDataEditorViewModel : INotifyPropertyChanged
	{
		#region Variables

		private readonly MatchDataEditorViewModelParameters _parameters;

		private IForecastData _forecastData;

		private IForecastData _correctForecastData;

		private bool _isWindowEnabled;
		private string _homeTeamName;
		private string _awayTeamName;
		private Dictionary<DateTime, string> _teamMatches;
		private KeyValuePair<DateTime, string> _selectedTeamMatch;
		private Dictionary<DateTime, string> _homeTeamMatches;
		private KeyValuePair<DateTime, string> _selectedHomeTeamMatch;
		private Dictionary<DateTime, string> _awayTeamMatches;
		private KeyValuePair<DateTime, string> _selectedAwayTeamMatch;

		private RelayCommand _editTeamMatchCommand;
		private RelayCommand _editHomeTeamMatchCommand;
		private RelayCommand _editAwayTeamMatchCommand;
		private RelayCommand _generateCommand;
		private RelayCommand _updateNamesCommand;

		#endregion

		#region Properties

		public string HomeTeamName
		{
			get { return _homeTeamName; }
			set
			{
				_homeTeamName = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("HomeTeamName"));
			}
		}

		public string AwayTeamName
		{
			get { return _awayTeamName; }
			set
			{
				_awayTeamName = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("AwayTeamName"));
			}
		}

		public bool IsWindowEnabled
		{
			get { return _isWindowEnabled; }
			set
			{
				_isWindowEnabled = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("IsWindowEnabled"));
			}
		}

		public List<CoefficientsViewModelItem> Coefficients { get; set; }

		public Dictionary<DateTime, string> TeamMatches
		{
			get { return _teamMatches ?? (_teamMatches = new Dictionary<DateTime, string>()); }
			set
			{
				_teamMatches = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("TeamMatches"));
			}
		}

		public KeyValuePair<DateTime, string> SelectedTeamMatch
		{
			get { return _selectedTeamMatch; }
			set
			{
				_selectedTeamMatch = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("SelectedTeamMatch"));
			}
		}

		public Dictionary<DateTime, string> HomeTeamMatches
		{
			get { return _homeTeamMatches ?? (_homeTeamMatches = new Dictionary<DateTime, string>()); }
			set
			{
				_homeTeamMatches = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("HomeTeamMatches"));
			}
		}

		public KeyValuePair<DateTime, string> SelectedHomeTeamMatch
		{
			get { return _selectedHomeTeamMatch; }
			set
			{
				_selectedHomeTeamMatch = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("SelectedHomeTeamMatch"));
			}
		}

		public Dictionary<DateTime, string> AwayTeamMatches
		{
			get { return _awayTeamMatches ?? (_awayTeamMatches = new Dictionary<DateTime, string>()); }
			set
			{
				_awayTeamMatches = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("AwayTeamMatches"));
			}
		}

		public KeyValuePair<DateTime, string> SelectedAwayTeamMatch
		{
			get { return _selectedAwayTeamMatch; }
			set
			{
				_selectedAwayTeamMatch = value;
				if (PropertyChanged == null) return;
				PropertyChanged(this, new PropertyChangedEventArgs("SelectedAwayTeamMatch"));
			}
		}

		public ICommand EditTeamMatchCommand
		{
			get { return _editTeamMatchCommand; }
		}

		public ICommand EditHomeTeamMatchCommand
		{
			get { return _editHomeTeamMatchCommand; }
		}

		public ICommand EditAwayTeamMatchCommand
		{
			get { return _editAwayTeamMatchCommand; }
		}

		public ICommand GenerateCommand
		{
			get { return _generateCommand; }
		}

		public ICommand UpdateNamesCommand
		{
			get { return _updateNamesCommand; }
		}

		#endregion

		#region Constructors

		public MatchDataEditorViewModel(MatchDataEditorViewModelParameters parameters)
		{
			if (parameters == null)
				throw new ArgumentNullException(string.Format("Parameters"));
			_parameters = parameters;

			if (_parameters.ForecastDataBuilder == null)
				throw new ArgumentNullException(string.Format("ForecastDataBuilder"));

			if (_parameters.WindowManager == null)
				throw new ArgumentNullException(string.Format("WindowManager"));

			if (_parameters.SoccerfameDataHelperFactory == null)
				throw new ArgumentNullException(string.Format("SoccerfameDataHelperFactory"));

			FillViewModel();
		}

		#endregion

		#region Internal Implementation

		private void FillViewModel()
		{
			_editTeamMatchCommand = new RelayCommand(EditTeamMatch);
			_editHomeTeamMatchCommand = new RelayCommand(EditHomeTeamMatch);
			_editAwayTeamMatchCommand = new RelayCommand(EditAwayTeamMatch);
			_generateCommand = new RelayCommand(Generate);
			_updateNamesCommand = new RelayCommand(UpdateNames);

			var worker = new BackgroundWorker();
			worker.DoWork += FillViewModel_DoWork;
			worker.RunWorkerCompleted += FillViewModel_DoWorkComplete;
			worker.RunWorkerAsync();
		}

		private void FillTeamMatchesViewModel()
		{
			if (_correctForecastData.PersonalConfrontationStatistics != null
				&& _correctForecastData.PersonalConfrontationStatistics.Matches != null)
			{
				TeamMatches = _correctForecastData.PersonalConfrontationStatistics.Matches.OrderByDescending(m => m.Date)
					.ToDictionary(k => k.Date, v => v.MatchResultWithDate);
				SelectedTeamMatch = TeamMatches.FirstOrDefault();
			}
		}

		private void FillHomeTeamMatchesViewModel()
		{
			if (_correctForecastData.HomeTeam != null
				&& _correctForecastData.HomeTeam.LastMatches != null)
			{
				HomeTeamMatches = _correctForecastData.HomeTeam.LastMatches.OrderByDescending(m => m.Date)
					.ToDictionary(k => k.Date, v => v.MatchResultWithDate);
				SelectedHomeTeamMatch = HomeTeamMatches.FirstOrDefault();
			}
		}

		private void FillAwayTeamMatchesViewModel()
		{
			if (_correctForecastData.AwayTeam != null
				&& _correctForecastData.AwayTeam.LastMatches != null)
			{
				AwayTeamMatches = _correctForecastData.AwayTeam.LastMatches.OrderByDescending(m => m.Date)
					.ToDictionary(k => k.Date, v => v.MatchResultWithDate);
				SelectedAwayTeamMatch = AwayTeamMatches.FirstOrDefault();
			}
		}

		private void FillViewModel_DoWork(object sender, DoWorkEventArgs e)
		{
			Coefficients = new List<CoefficientsViewModelItem>
			{
				new CoefficientsViewModelItem { Type = CoefficientType.Winner12 },
				new CoefficientsViewModelItem { Type = CoefficientType.GoalCountOver2 },
				new CoefficientsViewModelItem { Type = CoefficientType.BothToScore }
			};
			TeamMatches = new Dictionary<DateTime, string>();

			_forecastData = _parameters.ForecastDataBuilder.Generate(_parameters.Url);
			_correctForecastData = _forecastData != null ? _forecastData.Clone() as IForecastData : null;

			if (_correctForecastData == null) return;

			HomeTeamName = _correctForecastData.HomeTeam != null ? _correctForecastData.HomeTeam.Name : string.Empty;
			AwayTeamName = _correctForecastData.AwayTeam != null ? _correctForecastData.AwayTeam.Name : string.Empty;

			FillTeamMatchesViewModel();
			FillHomeTeamMatchesViewModel();
			FillAwayTeamMatchesViewModel();
		}

		private void FillViewModel_DoWorkComplete(object sender, RunWorkerCompletedEventArgs e)
		{
			IsWindowEnabled = true;
		}

		private void EditTeamMatch(object parameter)
		{
			if (_correctForecastData.PersonalConfrontationStatistics == null
				|| _correctForecastData.PersonalConfrontationStatistics.Matches == null)
				return;

			var match = _correctForecastData.PersonalConfrontationStatistics.Matches
				.FirstOrDefault(m => m.Date == SelectedTeamMatch.Key);
			_parameters.WindowManager.ShowMatchEventsEditorWindow(match,
				m =>
				{
					if (match != null)
						match.Update(m);
					FillTeamMatchesViewModel();
				});
		}

		private void EditHomeTeamMatch(object parameter)
		{
			if (_correctForecastData.HomeTeam == null
				|| _correctForecastData.HomeTeam.LastMatches == null)
				return;

			var match = _correctForecastData.HomeTeam.LastMatches
				.FirstOrDefault(m => m.Date == SelectedHomeTeamMatch.Key);
			_parameters.WindowManager.ShowMatchEventsEditorWindow(match,
				m =>
				{
					if (match != null)
						match.Update(m);
					FillHomeTeamMatchesViewModel();
				});
		}

		private void EditAwayTeamMatch(object parameter)
		{
			if (_correctForecastData.AwayTeam == null
				|| _correctForecastData.AwayTeam.LastMatches == null)
				return;

			var match = _correctForecastData.AwayTeam.LastMatches
				.FirstOrDefault(m => m.Date == SelectedAwayTeamMatch.Key);
			_parameters.WindowManager.ShowMatchEventsEditorWindow(match,
				m =>
				{
					if (match != null)
						match.Update(m);
					FillAwayTeamMatchesViewModel();
				});
		}

		private void Generate(object parameter)
		{
			if (_correctForecastData.HomeTeam != null)
				_correctForecastData.HomeTeam.Name = HomeTeamName;
			if (_correctForecastData.AwayTeam != null)
				_correctForecastData.AwayTeam.Name = AwayTeamName;

			if (_correctForecastData.PersonalConfrontationStatistics != null)
			{
				_correctForecastData.PersonalConfrontationStatistics.HomeTeamName = HomeTeamName;
				_correctForecastData.PersonalConfrontationStatistics.AwayTeamName = AwayTeamName;
			}

			if (_correctForecastData.Coefficients == null)
				_correctForecastData.Coefficients = new Coefficients();

			if (Coefficients != null)
			{
				foreach (var coefficient in Coefficients)
				{
					double valueOne;
					double.TryParse(coefficient.ValueOne, out valueOne);
					double valueSecond;
					double.TryParse(coefficient.ValueSecond, out valueSecond);

					var coef = new Coefficient
					{
						FirstCoefficient = valueOne,
						SecondCoefficient = valueSecond
					};

					switch (coefficient.Type)
					{
						case CoefficientType.Winner12:
							_correctForecastData.Coefficients.TeamWinner = coef.Clone() as ICoefficient;
							break;

						case CoefficientType.GoalCountOver2:
							_correctForecastData.Coefficients.GoalCount = coef.Clone() as ICoefficient;
							break;

						case CoefficientType.BothToScore:
							_correctForecastData.Coefficients.BothToScore = coef.Clone() as ICoefficient;
							break;
					}
				}
			}

			_parameters.WindowManager.ShowForecastEditorWindow(_correctForecastData, _parameters.MatchType);
		}

		private void UpdateNames(object parameter)
		{
			IsWindowEnabled = false;

			var worker = new BackgroundWorker();
			worker.DoWork += UpdateNames_DoWork;
			worker.RunWorkerCompleted += UpdateNames_DoWorkComplete;
			worker.RunWorkerAsync();
		}

		private void UpdateNames_DoWork(object sender, DoWorkEventArgs e)
		{
			if (_forecastData.HomeTeam != null && _forecastData.HomeTeam.Name != HomeTeamName
				&& _parameters.SoccerfameDataHelperFactory.TeamNamesService != null)
				_parameters.SoccerfameDataHelperFactory.TeamNamesService.Save(HomeTeamName, _forecastData.HomeTeam.Name);

			if (_forecastData.AwayTeam != null && _forecastData.AwayTeam.Name != AwayTeamName
				&& _parameters.SoccerfameDataHelperFactory.TeamNamesService != null)
				_parameters.SoccerfameDataHelperFactory.TeamNamesService.Save(AwayTeamName, _forecastData.AwayTeam.Name);

			_correctForecastData.UpdateName(HomeTeamName, true);
			_correctForecastData.UpdateName(AwayTeamName, false);

			FillTeamMatchesViewModel();
			FillHomeTeamMatchesViewModel();
			FillAwayTeamMatchesViewModel();
		}

		private void UpdateNames_DoWorkComplete(object sender, RunWorkerCompletedEventArgs e)
		{
			IsWindowEnabled = true;
		}

		#endregion

		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		protected virtual void OnPropertyChanged(string propertyName)
		{
			var handler = PropertyChanged;
			if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
		}

		#endregion
	}
}
